package net.esj.basic.utils.writer.json;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.validation.Valid;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.hibernate.collection.internal.PersistentSet;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;

import net.esj.basic.annotation.IgnorePrint;
import net.esj.basic.dao.querybuilder.QueryBuilder;
import net.esj.basic.plugins.view.easyui.utils.EasyUiFormUtil;
import net.esj.basic.utils.DateFormat;
import net.esj.basic.utils.JavaProtoType;
import net.esj.basic.utils.writer.Signed;
import net.esj.basic.utils.writer.WriteException;
import net.esj.basic.utils.writer.WriterCode;

public class EasyUiFormHibeJsonWriter extends HibenateJsonWriter {

	@Override
	public String write(Object object, WriterCode code) throws WriteException {
		if (code == WriterCode.FORM) {
			Map reval = new HashMap();
			resolveObject(object, "entity", reval,null);
			return super.write(reval, null,code);
		} else {
			return super.write(object, code);
		}
	}

	@Override
	public String write(Object object, Signed signed, WriterCode code)
			throws WriteException {
		if (code == WriterCode.FORM) {
			Map reval = new HashMap();
			resolveObject(object, "entity", reval,signed);
			return super.write(reval,signed, code);
		} else {
			return super.write(object, signed,code);
		}
	}

	protected void resolveObject(Object o, String prefex, Map reval,Signed signed) throws WriteException {
		PropertyDescriptor[] origDescriptors = BeanUtilsBean.getInstance()
				.getPropertyUtils().getPropertyDescriptors(o);
		for (int i = 0; i < origDescriptors.length; i++) {
			String name = origDescriptors[i].getName();
			if ("class".equals(name)) {
				continue;
			}
			if(origDescriptors[i].getReadMethod()==null ){
        		continue;
        	}
			if(origDescriptors[i].getReadMethod().isAnnotationPresent(IgnorePrint.class)){
            	continue;
            }
			Signed sig = origDescriptors[i].getPropertyType().getAnnotation(Signed.class);
        	sig = origDescriptors[i].getReadMethod().getAnnotation(Signed.class);
        	boolean can = canWrite(sig, signed);
        	if(!can){
        		continue;
        	}
			if (BeanUtilsBean.getInstance().getPropertyUtils()
					.isReadable(o, name)) {
				try {
					Object value = BeanUtilsBean.getInstance()
							.getPropertyUtils().getSimpleProperty(o, name);
					name = proxyJsonObjectName(name, value, signed, WriterCode.NULL);
					value = proxyCheck(value);
					if (value == null) {
						continue;
					}
					if (JavaProtoType.JAVA_PROTO_TYPE
							.contains(value.getClass())) {
						reval.put(prefex + "." + name, value);
					} else if (JavaProtoType.JAVA_ARRAY_TYPE.contains(value
							.getClass())) {
						// for(int j=0;j<Array.getLength(value);j++){
						// toJSONString(Array.get(value, j),
						// "'"+prefex+"."+name+"["+i+"]'", reval);
						// toJSONString(Array.get(value, j),
						// prefex+"."+name+"["+i+"]", reval);
						// }
						reval.put(prefex + "." + name, value);
						// toJSONString(value, prefex+"."+name, reval);
					} else if (value instanceof Enum) {
						// reval.put("'"+prefex+"."+name+"'",
						// ((Enum)value).name());
						reval.put(prefex + "." + name, ((Enum) value).name());
					} else if (value instanceof Map) {
						for (Object key : ((Map) value).keySet()) {
							// toJSONString(((Map)value).get(key),"'"+prefex+"."+name+"."+key.toString()+"'",
							// reval);
							resolveObject(((Map) value).get(key), prefex + "."
									+ name + "." + key.toString(), reval,signed);
						}
					} else if (value instanceof Collection) {
						Iterator it = ((Collection) value).iterator();
						int j = 0;
						while (it.hasNext()) {
							Object v = it.next();
							// toJSONString(v,"'"+prefex+"."+name+"["+i+"]'",
							// reval);
							resolveObject(v, prefex + "." + name + "[" + i
									+ "]", reval,signed);
							i++;
						}
					} else if (value instanceof Date) {
						// reval.put("'"+prefex+"."+name+"'",
						// DateFormat.toString(((Date)value),
						// DateFormat.DEFAULT_DATETIME_FORMAT_SEC));
						reval.put(prefex + "." + name, DateFormat.toString(
								((Date) value),
								DateFormat.DEFAULT_DATETIME_FORMAT_SEC));
					} else {
						resolveObject(value, prefex + "." + name, reval,signed);
					}
				} catch (NoSuchMethodException e) {
					throw new WriteException(e);
				} catch (IllegalAccessException e) {
					throw new WriteException(e);
				} catch (InvocationTargetException e) {
					throw new WriteException(e);
				}
			}
		}
	}

	@Override
	protected String proxyJsonObjectName(String name, Object target,
			Signed signed, WriterCode code) {
		if(target instanceof HibernateProxy){
			return name+".id";
		}
		return name;
	}

}
